package com.acme.bankapp.service.bank;

import com.acme.bankapp.domine.account.Account;
import com.acme.bankapp.domine.account.CheckingAccount;
import com.acme.bankapp.domine.account.SavingAccount;
import com.acme.bankapp.domine.bank.Bank;
import com.acme.bankapp.domine.client.Client;
import com.acme.bankapp.domine.client.Gender;
import com.acme.bankapp.exceptions.*;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class BankDataLoader {
    private static final String INVALID_GENDER_EXCEPTION_MESSAGE =
            "Invalid gender";
    private static final String UNABLE_TO_PARSE_BALANCE_EXCEPTION_MESSAGE =
            "Unable to parse balance";
    private static final String INVALID_ACCOUNT_TYPE_EXCEPTION_MESSAGE =
            "Invalid account type";

    private static BankService bankService;

    public void load(final Bank bank, final String path)
            throws IOException {
        FileReader in = new FileReader(path);
        BufferedReader bufIn = new BufferedReader(in);
        String line = bufIn.readLine();
        while ((line != null) && ("".compareTo(line) != 0)) {
            addClientFromString(bank, line);
            line = bufIn.readLine();
        }
        bufIn.close();
        in.close();
    }

    public static boolean addClientFromString(final Bank bank,
            final String line) {
        String[] clientLine = line.split(";");

        Map<String, String> paramValueMap = new HashMap<String, String>();
        for (String aClientLine : clientLine) {
            String[] paramValue = aClientLine.split("=");
            paramValueMap.put(paramValue[0], paramValue[1]);
        }

        try {
            createBankEntities(paramValueMap, bank);
        } catch (BankException e) {
            return false;
        }
        return true;
    }

    private static void createBankEntities(
            final Map<String, String> paramValueMap, final Bank bank)
            throws BankException {

        String accountType =    paramValueMap.get("accounttype");
        String balance =        paramValueMap.get("balance");
        String overdraft =      paramValueMap.get("overdraft");
        String name =           paramValueMap.get("name");
        String gender =         paramValueMap.get("gender");

        Gender genderType = null;
        if ("m".equals(gender)) {
            genderType = Gender.MALE;
        } else if ("f".equals(gender)) {
            genderType = Gender.FEMALE;
        } else {
            throw new BankException(INVALID_GENDER_EXCEPTION_MESSAGE);
        }

        Client client = null;
        try {
            client = bankService.addClient(bank, name, genderType);
        } catch (ClientExistsException e) {
            System.out.println(e.getMessage());
        }

        addAccount(accountType, balance, overdraft, client);
    }

    private static void addAccount(final String accountType,
            final String balance, final String overdraft, final Client client)
            throws BankException {

        double balanceAsDouble = 0;
        try {
            balanceAsDouble = Double.parseDouble(balance);
        } catch (NumberFormatException e) {
            throw new BankException(UNABLE_TO_PARSE_BALANCE_EXCEPTION_MESSAGE);
        }


        Account account = null;
        if ("c".equals(accountType)) {
            double overdraftAsDouble = 0;
            try {
                overdraftAsDouble = Double.parseDouble(overdraft);
            } catch (NumberFormatException e) {
                overdraftAsDouble = 0;
            }
            account = new CheckingAccount(balanceAsDouble, overdraftAsDouble);
        } else if ("s".equals(accountType)) {
            account = new SavingAccount(balanceAsDouble);
        } else {
            throw new BankException(INVALID_ACCOUNT_TYPE_EXCEPTION_MESSAGE);
        }
        client.addAccount(account);
    }


    public void setBankService(final BankService bankService) {
        BankDataLoader.bankService = bankService;
    }
}
